package chat

import (
	"bufio"
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"log"
	"net/http"
	"regexp"
	"sync"
)

type Server struct {
	url     string
	clients map[string]*Client
	addCli  chan *Client
	delCli  chan *Client
	sendAll chan *Message
}

//存放所有Server Room的列表
var RoomList sync.Map

func NewServer(pattern string) *Server {

	return &Server{
		url:     pattern,
		clients: make(map[string]*Client),
		addCli:  make(chan *Client),
		delCli:  make(chan *Client),
		sendAll: make(chan *Message),
	}
}

//有新的连接
func (s *Server) Add(c *Client) {

	s.addCli <- c

}

//有断开的连接
func (s *Server) Del(c *Client) {

	s.delCli <- c

}

//点对点发送
func (s *Server) SendToOne(name string, m *Message) {

	s.clients[name].Write(m)

}

//广播
func (s *Server) SendAll(m *Message) {
	for _, client := range s.clients {
		log.Println(client)
		client.Write(m)
	}
}

//获取用户列表中所有的keys
func getKeys(m map[string]*Client) []string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
	return keys
}

//及时广播更新用户列表
func (s *Server) UpdateUserList() {
	for _, c := range s.clients {
		users, _ := json.Marshal(getKeys(s.clients))
		c.conn.Write(users)
	}

}

// websocket handler
func (s *Server) onConnected(conn *websocket.Conn) {

	//读取客户端的username
	r := bufio.NewReader(conn)
	data := make([]byte, 256)
	n, err := r.Read(data)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(data[:n]))
	// 生成新的客户端
	client := NewClient(conn, s, string(data[:n]))
	//go ServerHandler(s)
	//将客户端加入map中
	s.Add(client)
	client.Listen()

}

//定义过滤器，满足/ws/*才能被连接
func ConnFilterMiddle() func(conn *websocket.Conn) {

	return func(conn *websocket.Conn) {

		reg, err := regexp.Compile("^/ws/[a-z0-9].*")
		if err != nil {
			fmt.Println(err)
			return
		}
		if b := reg.MatchString(conn.Request().URL.Path); b {
			//判断是否已经存在这个房间，不存在就添加到roomList,存在并发安全问题，下一步优化
			if srv, ok := RoomList.Load(conn.Request().URL.Path); ok {
				s := srv.(*Server)
				s.onConnected(conn)
			} else {
				//匹配通过创建一个房间room,并加入roomList,
				s := NewServer(conn.Request().URL.Path)
				go ServerHandler(s)
				RoomList.Store(conn.Request().URL.Path, s)
				s.onConnected(conn)
			}

		} else {
			log.Println("bad connection...")
			conn.WriteClose(http.StatusBadRequest)
		}

	}

}

func ServerHandler(s *Server) {

	for {
		select {
		//每个用户连接上之后，通知其它在线用户
		case client := <-s.addCli:
			s.clients[client.name] = client
			s.UpdateUserList()
			log.Println("新的连接", client)
		case client := <-s.delCli:
			log.Println("断开一个连接", client)
			delete(s.clients, client.name)
			s.UpdateUserList()
		}
	}

}

func Listen() {

	http.Handle("/", websocket.Handler(ConnFilterMiddle()))

	http.ListenAndServe(":8081", nil)

}
